package com.test.exoplayertest.player.manager;

import android.app.Activity;
import android.content.Context;
import android.media.AudioManager;
import android.net.Uri;
import android.os.Handler;
import android.os.Looper;
import android.text.TextUtils;
import android.view.TextureView;
import android.view.WindowManager;

import com.google.android.exoplayer2.C;
import com.google.android.exoplayer2.ExoPlayerFactory;
import com.google.android.exoplayer2.SimpleExoPlayer;
import com.google.android.exoplayer2.extractor.DefaultExtractorsFactory;
import com.google.android.exoplayer2.source.ExtractorMediaSource;
import com.google.android.exoplayer2.source.MediaSource;
import com.google.android.exoplayer2.source.dash.DashMediaSource;
import com.google.android.exoplayer2.source.dash.DefaultDashChunkSource;
import com.google.android.exoplayer2.source.hls.HlsMediaSource;
import com.google.android.exoplayer2.source.smoothstreaming.DefaultSsChunkSource;
import com.google.android.exoplayer2.source.smoothstreaming.SsMediaSource;
import com.google.android.exoplayer2.trackselection.AdaptiveTrackSelection;
import com.google.android.exoplayer2.trackselection.DefaultTrackSelector;
import com.google.android.exoplayer2.trackselection.TrackSelection;
import com.google.android.exoplayer2.trackselection.TrackSelector;
import com.google.android.exoplayer2.upstream.BandwidthMeter;
import com.google.android.exoplayer2.upstream.DataSource;
import com.google.android.exoplayer2.upstream.DefaultBandwidthMeter;
import com.google.android.exoplayer2.upstream.DefaultDataSourceFactory;
import com.google.android.exoplayer2.upstream.DefaultHttpDataSourceFactory;
import com.google.android.exoplayer2.upstream.HttpDataSource;
import com.google.android.exoplayer2.util.Util;
import com.test.exoplayertest.player.interfaces.PlayerEventInterface;
import com.test.exoplayertest.player.utils.PlayerUtil;

import java.lang.ref.WeakReference;

/**
 * @author wuxiaotao on 2017/6/15.
 */

public class PlayerControl implements PlayerEventInterface<TextureView> {

    private static final int FLAG_SHOW_UI_WARNINGS = 1 << 10;
    private SimpleExoPlayer mExoPlayer;
    private WeakReference<Context> mContextWeakReference;
    private Handler mHandler = new Handler(Looper.getMainLooper());
    private DataSource.Factory mediaDataSourceFactory;
    private static final DefaultBandwidthMeter BANDWIDTH_METER = new DefaultBandwidthMeter();
    private MediaSource mediaSource;
    private long resumePosition = C.TIME_UNSET;
    private boolean pasuePlayerReady = true;
    private TextureView mTextureView;

    //-----------音频相关---------
    private final AudioManager mAudioManager;
    private int mBaseVolumeValue;

    public PlayerControl(Context context) {
        mContextWeakReference = new WeakReference<Context>(context);
        initPlayer();
        mAudioManager = (AudioManager) context.getApplicationContext().getSystemService(Context.AUDIO_SERVICE);
    }

    private void initPlayer() {
        if (mExoPlayer != null) {
            return;
        }
        Context context = mContextWeakReference.get();
        if (null != context) {
            BandwidthMeter bandwidthMeter = new DefaultBandwidthMeter();
            TrackSelection.Factory videoTrackSelectionFactory = new AdaptiveTrackSelection.Factory(bandwidthMeter);
            TrackSelector trackSelector = new DefaultTrackSelector(videoTrackSelectionFactory);
            mExoPlayer = ExoPlayerFactory.newSimpleInstance(context, trackSelector);
            mediaDataSourceFactory = buildDataSourceFactory(true);
            if (null != mTextureView) {
                attach(mTextureView);
            }
        }
    }

    @Override
    public void attach(TextureView textureView) {
        initPlayer();
        if(null == mTextureView){
            mTextureView = textureView;
            mExoPlayer.setVideoTextureView(textureView);
        }else if (mTextureView != null && mTextureView != textureView) {
            mExoPlayer.clearVideoTextureView(mTextureView);
            mTextureView = textureView;
            mExoPlayer.setVideoTextureView(textureView);
        }
        mExoPlayer.setPlayWhenReady(true);
    }

    @Override
    public void detach() {
        mExoPlayer.setPlayWhenReady(false);
//        mExoPlayer.clearVideoTextureView(mTextureView);
//        mTextureView = null;
    }

    @Override
    public void startPlay(String url, String type) {
        Uri uri = Uri.parse(url);
        mediaSource = buildMediaSource(uri, type);
        mExoPlayer.prepare(mediaSource);
        mExoPlayer.setPlayWhenReady(true);
    }

    @Override
    public void release() {
        //释放播放器时，记录上次播放位置  resume时跳转
        updateResumePosition();
        pasuePlayerReady = mExoPlayer.getPlayWhenReady();
        mExoPlayer.clearVideoTextureView(mTextureView);
        mExoPlayer.release();
        setKeepScreenOn(false);
        mTextureView = null;
        mExoPlayer = null;
    }

    @Override
    public void resume() {
        initPlayer();
        if (null != mediaSource) {
            boolean haveResumePosition = resumePosition != C.TIME_UNSET;
            if (haveResumePosition) {
                mExoPlayer.seekTo(resumePosition);
            }
            mExoPlayer.prepare(mediaSource, !haveResumePosition, false);
            mExoPlayer.setPlayWhenReady(pasuePlayerReady);
        }
    }

    public void setKeepScreenOn(boolean keepScreenOn) {
        if (null != mTextureView && keepScreenOn != mTextureView.getKeepScreenOn()) {
            mTextureView.setKeepScreenOn(keepScreenOn);
        }
    }

    private void updateResumePosition() {
        resumePosition = mExoPlayer.isCurrentWindowSeekable() ? Math.max(0, mExoPlayer.getCurrentPosition())
                : C.TIME_UNSET;
    }

    private void clearResumePosition() {
        resumePosition = C.TIME_UNSET;
    }

    public SimpleExoPlayer getExoPlayer() {
        return mExoPlayer;
    }

    private MediaSource buildMediaSource(Uri uri, String overrideExtension) {
        int type = TextUtils.isEmpty(overrideExtension) ? Util.inferContentType(uri)
                : Util.inferContentType("." + overrideExtension);
        switch (type) {
            case C.TYPE_SS:
                return new SsMediaSource(uri, buildDataSourceFactory(false),
                        new DefaultSsChunkSource.Factory(mediaDataSourceFactory), mHandler, null);
            case C.TYPE_DASH:
                return new DashMediaSource(uri, buildDataSourceFactory(false),
                        new DefaultDashChunkSource.Factory(mediaDataSourceFactory), mHandler, null);
            case C.TYPE_HLS:
                return new HlsMediaSource(uri, mediaDataSourceFactory, mHandler, null);
            case C.TYPE_OTHER:
                return new ExtractorMediaSource(uri, mediaDataSourceFactory, new DefaultExtractorsFactory(),
                        mHandler, null);
            default: {
                throw new IllegalStateException("Unsupported type: " + type);
            }
        }
    }


    private DataSource.Factory buildDataSourceFactory(boolean useBandwidthMeter) {
        return buildDataSourceFactory(useBandwidthMeter ? BANDWIDTH_METER : null);
    }

    public DataSource.Factory buildDataSourceFactory(DefaultBandwidthMeter bandwidthMeter) {
        Context context = mContextWeakReference.get();
        return new DefaultDataSourceFactory(context.getApplicationContext(), bandwidthMeter, buildHttpDataSourceFactory(bandwidthMeter));
    }

    public HttpDataSource.Factory buildHttpDataSourceFactory(DefaultBandwidthMeter bandwidthMeter) {
        Context context = mContextWeakReference.get();
        return new DefaultHttpDataSourceFactory(PlayerUtil.getUserAgent(context.getApplicationContext(), "playerTest"), bandwidthMeter);
    }

    // ------ 音频相关 ------

    private int mMaxVolue = -1;

    public int getMaxVolume() {
        if (mMaxVolue > 0) {
            return mMaxVolue;
        }
        return mMaxVolue = this.mAudioManager.getStreamMaxVolume(AudioManager.STREAM_MUSIC);
    }

    private int getCurrentVolume() {
        return this.mAudioManager.getStreamVolume(AudioManager.STREAM_MUSIC);
    }

    public void updateDownVolume() {
        mBaseVolumeValue = getCurrentVolume();
    }

    /**
     * 手势调整音量
     */
    public int setVolume(float incremental) {
        int max = this.getMaxVolume();
        int target = (int) (this.mBaseVolumeValue + incremental * max);
        if (target >= max) {
            target = max;
        } else if (target < 0) {
            target = 0;
        }
        this.setVolume(target);
        return target;
    }

    private void setVolume(int value) {
        if ((value >= 0) && (value <= this.getMaxVolume())) {
            this.mAudioManager.setStreamVolume(AudioManager.STREAM_MUSIC,
                    value, FLAG_SHOW_UI_WARNINGS);
        }
    }

    //----亮度调节相关--------
    public static final int MAX_BRIGHTNESS_VALUE = 255;
    private int mBaseBrightnessValue = -1;

    public void updateDownBrightness() {
        mBaseBrightnessValue = getCurrentBrightness();
    }

    private void setBrightness(int value) {
        Context context = mContextWeakReference.get();
        if (null == context) {
            return;
        }
        Activity activity = (Activity) context;
        float target = (float) value / MAX_BRIGHTNESS_VALUE;
        if (target > 1.0f) {
            target = 1.0f;
        }
        if (target < 0.1f) {
            target = 0.1f;
        }
        WindowManager.LayoutParams wl = activity.getWindow()
                .getAttributes();
        wl.screenBrightness = target;

        activity.getWindow().setAttributes(wl);
    }

    public int setBrightness(float incremental) {
        int target = (int) (this.mBaseBrightnessValue + incremental * MAX_BRIGHTNESS_VALUE);
        if (target >= MAX_BRIGHTNESS_VALUE) {
            target = MAX_BRIGHTNESS_VALUE;
        } else if (target < 0) {
            target = 0;
        }
        this.setBrightness(target);
        return target;
    }

    private int getCurrentBrightness() {
        Context context = mContextWeakReference.get();
        if (null == context) {
            return 0;
        }
        Activity activity = (Activity) context;
        float brightness = activity.getWindow().getAttributes().screenBrightness;
        if (brightness < 0) {
            brightness = 0.5f;
        }
        return (int) (brightness * MAX_BRIGHTNESS_VALUE);
    }
}
